package com.qiudao.commonutil.util;


import com.qiudao.commonresult.exception.BizException;
import com.google.common.base.Strings;
import com.qiudao.commonutil.annotation.ChildrenList;
import com.qiudao.commonutil.annotation.ParentId;
import com.qiudao.commonutil.annotation.SortId;
import com.qiudao.commonutil.base.TreeNode;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Description: 排序工具类 
 * @author: gdc
 * @date: 2019/9/1
 * @version 1.0
 */
public class SortUtils {
    /**
     * 根据注解ParentId和Id进行树状排序，将子节点放入ChildrenList中
     *
     * @param list 1. 如果需要有序，需要在传入前已经进行好排序。
     *             2. 默认是所有的Id都是不同的，所以要加入全部或者未分类的元素，需要设置唯一的Id。排序之后，由业务方自己更换。
     * @param <T>
     * @return
     */
    public static <T> List<T> makeSortTree(List<T> list) {

        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList();
        }

        List<T> resultList = new ArrayList<>();
        LinkedHashMap<String, TreeNode> nodeMap = new LinkedHashMap<>();

        for (Object object : list) {
            Field[] fields = object.getClass().getDeclaredFields();
            if (fields == null) {
                break;
            }

            TreeNode node = new TreeNode();

            for (Field field : fields) {

                if (field.getAnnotation(SortId.class) != null && String.class.getName().equals(field.getType().getName())) {
                    try {
                        Method method = object.getClass().getMethod("get" + getMethodName(field.getName()), null);
                        String id = (String) method.invoke(object, null);
                        node.setId(id);
                    } catch (Exception e) {
                        throw new BizException(e.getMessage());
                    }
                }

                if (field.getAnnotation(ParentId.class) != null && String.class.getName().equals(field.getType().getName())) {
                    try {
                        Method method = object.getClass().getMethod("get" + getMethodName(field.getName()), null);
                        String parentId = (String) method.invoke(object, null);
                        node.setParentId(parentId);
                    } catch (Exception e) {
                        throw new BizException(e.getMessage());
                    }
                }
            }

            node.setObject(object);
            nodeMap.put(node.getId(), node);
        }

        Iterator<String> iterator = nodeMap.keySet().iterator();

        while (iterator.hasNext()) {
            TreeNode node2 = nodeMap.get(iterator.next());
            TreeNode parentNode = nodeMap.get(node2.getParentId());

            if (parentNode == null) {
                continue;
            }

            T t4Parent = (T) parentNode.getObject();
            Field[] fields2 = t4Parent.getClass().getDeclaredFields();
            if (fields2 == null) {
                break;
            }
            for (Field field : fields2) {

                if (field.getAnnotation(ChildrenList.class) != null) {
                    try {
                        Method getMethod = t4Parent.getClass().getMethod("get" + getMethodName(field.getName()), null);
                        List<T> list1 = (List<T>) getMethod.invoke(t4Parent, null);
                        if (list1 == null) {
                            list1 = new ArrayList<T>();
                        }
                        T t1 = (T) node2.getObject();
                        list1.add(t1);
                        Method setMethod = t4Parent.getClass().getMethod("set" + getMethodName(field.getName()), List.class);
                        setMethod.invoke(t4Parent, list1);
                    } catch (Exception e) {
                        throw new BizException(e.getMessage());
                    }
                }
            }
        }

        Iterator<String> iterator2 = nodeMap.keySet().iterator();
        while (iterator2.hasNext()) {
            TreeNode node3 = nodeMap.get(iterator2.next());
            if (Strings.isNullOrEmpty(node3.getParentId())) {
                resultList.add((T) node3.getObject());
            }
        }
        return resultList;
    }

    private static String getMethodName(String fildeName) throws Exception {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }
}
